home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / LIB / GLE / ex_cut_round.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  46.8 KB  |  1,314 lines

  1.  
  2. /*
  3.  * MODULE NAME: ex_cut_round.c
  4.  *
  5.  * FUNCTION:
  6.  * This module contains code that draws extrusions with cut or round
  7.  * join styles. The cut join style is a beveled edge.
  8.  * The code also inserts colors and normals if appropriate.
  9.  *
  10.  * HISTORY:
  11.  * written by Linas Vepstas August/September 1991
  12.  * split into multiple compile units, Linas, October 1991
  13.  * added normal vectors Linas, October 1991
  14.  * Fixed filleting problem, Linas February 1993
  15.  * Modified to handle round joins as well (based on common code),
  16.  *                           Linas, March 1993
  17.  * work around OpenGL's lack of support for concave polys, June 1994
  18.  */
  19.  
  20. #include <stdlib.h>
  21. #include <math.h>
  22. #include <string.h>    /* for the memcpy() subroutine */
  23. #include <GL/tube.h>
  24. #include "port.h" 
  25. #include "gutil.h"
  26. #include "vvector.h"
  27. #include "tube_gc.h"
  28. #include "extrude.h"
  29. #include "intersect.h"
  30. #include "segment.h"
  31.  
  32.  
  33. #ifdef NONCONCAVE_CAPS
  34.  
  35. /* ============================================================ */
  36. /* 
  37.  * This subroutine draws a flat cap, to close off the cut ends 
  38.  * of the cut-style join.  Because OpenGL doe not natively handle 
  39.  * concave polygons, this will cause some artifacts to appear on the
  40.  * screen.
  41.  */
  42.  
  43. void draw_cut_style_cap_callback (int iloop,
  44.                                   double cap[][3], 
  45.                                   float face_color[3],
  46.                                   gleDouble cut_vector[3],
  47.                                   gleDouble bisect_vector[3],
  48.                                   double norms[][3], 
  49.                                   int frontwards)
  50. {
  51.    int i;
  52.  
  53.    if (face_color != NULL) C3F (face_color);
  54.  
  55.    if (frontwards) {
  56.  
  57.       /* if lighting is on, specify the endcap normal */
  58.       if (cut_vector != NULL) {
  59.          /* if normal pointing in wrong direction, flip it. */
  60.          if (cut_vector[2] < 0.0) { 
  61.             VEC_SCALE (cut_vector, -1.0, cut_vector); 
  62.          }
  63.          N3F_D (cut_vector);
  64.       }
  65.       BGNPOLYGON();
  66.       for (i=0; i<iloop; i++) {
  67.          V3F_D (cap[i], i, FRONT_CAP);
  68.       }
  69.       ENDPOLYGON();
  70.    } else {
  71.  
  72.       /* if lighting is on, specify the endcap normal */
  73.       if (cut_vector != NULL) {
  74.          /* if normal pointing in wrong direction, flip it. */
  75.          if (cut_vector[2] > 0.0) 
  76.            { VEC_SCALE (cut_vector, -1.0, cut_vector); }
  77.          N3F_D (cut_vector);
  78.       }
  79.       /* the sense of the loop is reversed for backfacing culling */
  80.       BGNPOLYGON();
  81.       for (i=iloop-1; i>-1; i--) {
  82.          V3F_D (cap[i], i, BACK_CAP);
  83.       }
  84.       ENDPOLYGON();
  85.    }
  86.  
  87. }
  88.  
  89. #else /* NONCONCAVE_CAPS */
  90.  
  91. /* ============================================================ */
  92. /* 
  93.  * This subroutine draws a flat cap, to close off the cut ends 
  94.  * of the cut-style join.  Properly handles concave endcaps.
  95.  */
  96.  
  97. /* ARGSUSED4 */
  98. static void draw_cut_style_cap_callback (int iloop,
  99.                                   double cap[][3], 
  100.                                   float face_color[3],
  101.                                   gleDouble cut_vector[3],
  102.                                   gleDouble bisect_vector[3],
  103.                                   double norms[][3], 
  104.                                   int frontwards)
  105. {
  106.    int i;
  107. #ifdef OPENGL_10
  108.    GLUtriangulatorObj *tobj;
  109.    tobj = gluNewTess ();
  110.    gluTessCallback (tobj, GLU_BEGIN, glBegin);
  111.    gluTessCallback (tobj, GLU_VERTEX, glVertex3dv);
  112.    gluTessCallback (tobj, GLU_END, glEnd);
  113. #endif /* OPENGL_10 */
  114.  
  115.    if (face_color != NULL) C3F (face_color);
  116.  
  117.    if (frontwards) {
  118.  
  119.       /* if lighting is on, specify the endcap normal */
  120.       if (cut_vector != NULL) {
  121.          /* if normal pointing in wrong direction, flip it. */
  122.          if (cut_vector[2] < 0.0) { 
  123.             VEC_SCALE (cut_vector, -1.0, cut_vector); 
  124.          }
  125.          N3F_D (cut_vector);
  126.       }
  127. #ifdef GL_32
  128.       BGNPOLYGON();
  129.       for (i=0; i<iloop; i++) {
  130.          V3F_D (cap[i], i, FRONT_CAP);
  131.       }
  132.       ENDPOLYGON();
  133. #endif /* GL_32 */
  134. #ifdef OPENGL_10
  135.       gluBeginPolygon (tobj);
  136.       for (i=0; i<iloop; i++) {
  137.          gluTessVertex (tobj, cap[i], cap[i]);
  138.       }
  139.       gluEndPolygon (tobj);
  140. #endif /* OPENGL_10 */
  141.    } else {
  142.  
  143.       /* if lighting is on, specify the endcap normal */
  144.       if (cut_vector != NULL) {
  145.          /* if normal pointing in wrong direction, flip it. */
  146.          if (cut_vector[2] > 0.0) {
  147.             VEC_SCALE (cut_vector, -1.0, cut_vector); 
  148.          }
  149.          N3F_D (cut_vector);
  150.       }
  151.       /* the sense of the loop is reversed for backfacing culling */
  152. #ifdef GL_32
  153.       BGNPOLYGON();
  154.       for (i=iloop-1; i>-1; i--) {
  155.          V3F_D (cap[i], i, BACK_CAP);
  156.       }
  157.       ENDPOLYGON();
  158. #endif /* GL_32 */
  159. #ifdef OPENGL_10
  160.       gluBeginPolygon (tobj);
  161.       for (i=iloop-1; i>-1; i--) {
  162.          gluTessVertex (tobj, cap[i], cap[i]);
  163.       }
  164.       gluEndPolygon (tobj);
  165. #endif /* OPENGL_10 */
  166.    }
  167.  
  168. #ifdef OPENGL_10
  169.    gluDeleteTess (tobj);
  170. #endif /* OPENGL_10 */
  171.  
  172. }
  173. #endif /* NONCONCAVE_ENDCAPS */
  174.  
  175. /* ============================================================ */
  176. /* 
  177.  * This subroutine matchs the cap callback template, but is a no-op
  178.  */
  179.  
  180. /* ARGSUSED */
  181. void null_cap_callback (int iloop,
  182.                         double cap[][3], 
  183.                         float face_color[3],
  184.                         gleDouble cut_vector[3],
  185.                         gleDouble bisect_vector[3],
  186.                         double norms[][3], 
  187.                         int frontwards)
  188. {}
  189.  
  190. /* ============================================================ */
  191. /* 
  192.  * This little routine draws the little idd-biddy fillet triangle with
  193.  * the right  color, normal, etc.
  194.  *
  195.  * HACK ALERT -- there are two aspects to this routine/interface that
  196.  * are "unfinished".
  197.  * 1) the third point of the triangle should get a color thats
  198.  *    interpolated beween the front and back color.  The interpolant
  199.  *    is not currently being computed.  The error introduced by not 
  200.  *    doing this should be tiny and/or non-exitant in almost all 
  201.  *    expected uses of this code.
  202.  *
  203.  * 2) additional normal vectors should be supplied, and these should
  204.  *    be interpolated to fit.  Currently, this is not being done.  As
  205.  *    above, the expected error of not doing this should be tiny and/or
  206.  *    non-existant in almost all expected uses of this code.
  207.  */
  208. /* ARGSUSED6 */
  209. static void draw_fillet_triangle_plain
  210.                           (gleDouble va[3],
  211.                            gleDouble vb[3],
  212.                            gleDouble vc[3],
  213.                            int face,
  214.                            float front_color[3],
  215.                            float back_color[3])
  216. {
  217.  
  218.    if (front_color != NULL) C3F (front_color);
  219.    BGNTMESH (-5, 0.0);
  220.    if (face) {
  221.       V3F (va, -1, FILLET);
  222.       V3F (vb, -1, FILLET);
  223.    } else {
  224.       V3F (vb, -1, FILLET);
  225.       V3F (va, -1, FILLET);
  226.    }
  227.    V3F (vc, -1, FILLET);
  228.    ENDTMESH ();
  229.  
  230. }
  231.  
  232. /* ============================================================ */
  233. /* 
  234.  * This little routine draws the little idd-biddy fillet triangle with
  235.  * the right  color, normal, etc.
  236.  *
  237.  * HACK ALERT -- there are two aspects to this routine/interface that
  238.  * are "unfinished".
  239.  * 1) the third point of the triangle should get a color thats
  240.  *    interpolated beween the front and back color.  The interpolant
  241.  *    is not currently being computed.  The error introduced by not 
  242.  *    doing this should be tiny and/or non-exitant in almost all 
  243.  *    expected uses of this code.
  244.  *
  245.  * 2) additional normal vectors should be supplied, and these should
  246.  *    be interpolated to fit.  Currently, this is not being done.  As
  247.  *    above, the expected error of not doing this should be tiny and/or
  248.  *    non-existant in almost all expected uses of this code.
  249.  */
  250. /* ARGSUSED5 */
  251. static void draw_fillet_triangle_n_norms
  252.                           (gleDouble va[3],
  253.                            gleDouble vb[3],
  254.                            gleDouble vc[3],
  255.                            int face,
  256.                            float front_color[3],
  257.                            float back_color[3],
  258.                            double na[3],
  259.                            double nb[3])
  260. {
  261.  
  262.    if (front_color != NULL) C3F (front_color);
  263.    BGNTMESH (-5, 0.0);
  264.    if (__TUBE_DRAW_FACET_NORMALS) {
  265.       N3F_D (na);
  266.       if (face) {
  267.          V3F (va, -1, FILLET);
  268.          V3F (vb, -1, FILLET);
  269.       } else {
  270.          V3F (vb, -1, FILLET);
  271.          V3F (va, -1, FILLET);
  272.       }
  273.       V3F (vc, -1, FILLET);
  274.    } else {
  275.       if (face) {
  276.          N3F_D (na);
  277.          V3F (va, -1, FILLET);
  278.          N3F_D (nb);
  279.          V3F (vb, -1, FILLET);
  280.       } else {
  281.          N3F_D (nb);
  282.          V3F (vb, -1, FILLET);
  283.          N3F_D (na);
  284.          V3F (va, -1, FILLET);
  285.          N3F_D (nb);
  286.       }
  287.       V3F (vc, -1, FILLET);
  288.    }
  289.    ENDTMESH ();
  290.  
  291. }
  292.  
  293. /* ============================================================ */
  294.  
  295. static void draw_fillets_and_join_plain
  296.                     (int ncp, 
  297.                     gleDouble trimmed_loop[][3],
  298.                     gleDouble untrimmed_loop[][3], 
  299.                     int is_trimmed[],
  300.                     gleDouble bis_origin[3], 
  301.                     gleDouble bis_vector[3], 
  302.                     float front_color[3],
  303.                     float back_color[3],
  304.                     gleDouble cut_vector[3], 
  305.                     int face,
  306.                     void ((*cap_callback) (int iloop,
  307.                                   double cap[][3],
  308.                                   float face_color[3],
  309.                                   gleDouble cut_vector[3],
  310.                                   gleDouble bisect_vector[3],
  311.                                   double norms[][3],
  312.                                   int frontwards)))
  313. {
  314.    int istop;
  315.    int icnt, icnt_prev, iloop;
  316.    double *cap_loop;
  317.    gleDouble sect[3];
  318.    gleDouble tmp_vec[3];
  319.    int save_style;
  320.    int was_trimmed = FALSE;
  321.  
  322.    cap_loop = (double *) malloc ((ncp+3)*3*sizeof (double));
  323.    
  324.    /* if the first point on the contour isn't trimmed, go ahead and
  325.     * drop an edge down to the bisecting plane, (thus starting the 
  326.     * join).  (Only need to do this for cut join, its bad if done for
  327.     * round join).
  328.     *
  329.     * But if the first point is trimmed, keep going until one
  330.     * is found that is not trimmed, and start join there.  */
  331.  
  332.    icnt = 0;
  333.    iloop = 0;
  334.    if (!is_trimmed[0]) {
  335.       if (__TUBE_CUT_JOIN) {
  336.          VEC_SUM (tmp_vec, trimmed_loop[0], bis_vector);
  337.          INNERSECT (sect, 
  338.                     bis_origin,
  339.                     bis_vector,
  340.                     trimmed_loop[0],
  341.                     tmp_vec);
  342.          VEC_COPY ( (&cap_loop[3*iloop]), sect);
  343.          iloop ++;
  344.       }
  345.       VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[0])); 
  346.       iloop++;
  347.       icnt_prev = icnt;
  348.       icnt ++;
  349.    } else {
  350.  
  351.       /* else, loop until an untrimmed point is found */
  352.       was_trimmed = TRUE;
  353.       while (is_trimmed[icnt]) {
  354.          icnt_prev = icnt;
  355.          icnt ++;
  356.          if (icnt >= ncp) { 
  357.             free (cap_loop);
  358.             return;    /* oops - everything was trimmed */
  359.          }
  360.       }
  361.    }
  362.  
  363.    /* Start walking around the end cap.  Every time the end loop is
  364.     * trimmed, we know we'll need to draw a fillet triangle.  In
  365.     * addition, after every pair of visibility changes, we draw a cap. */
  366.    if (__TUBE_CLOSE_CONTOUR) {
  367.       istop = ncp;
  368.    } else {
  369.       istop = ncp-1;
  370.    }
  371.  
  372.    /* save the join style, and disable a closed contour.
  373.     * Need to do this so partial contours don't close up. */
  374.    save_style = gleGetJoinStyle ();
  375.    gleSetJoinStyle (save_style & ~TUBE_CONTOUR_CLOSED);
  376.  
  377.    for (; icnt_prev < istop; icnt_prev ++, icnt ++, icnt %= ncp) {
  378.  
  379.       /* There are four interesting cases for drawing caps and fillets:
  380.        *    1) this & previous point were trimmed.  Don't do anything, 
  381.        *       advance counter.
  382.        *    2) this point trimmed, previous not -- draw fillet, and 
  383.        *       draw cap.
  384.        *    3) this point not trimmed, previous one was -- compute
  385.        *       intersection point, draw fillet with it, and save 
  386.        *       point for cap contour.
  387.        *    4) this & previous point not trimmed -- save for endcap.
  388.        */
  389.  
  390.       /* Case 1 -- noop, just advance pointers */
  391.       if (is_trimmed[icnt_prev] && is_trimmed[icnt]) {
  392.       }
  393.  
  394.       /* Case 2 --  Hah! first point! compute intersect & draw fillet! */
  395.       if (is_trimmed[icnt_prev] && !is_trimmed[icnt]) {
  396.  
  397.          /* important note: the array "untrimmed" contains valid
  398.           * untrimmed data ONLY when is_trim is TRUE.  Otherwise, 
  399.           * only "trim" containes valid data */
  400.  
  401.          /* compute intersection */
  402.          INNERSECT (sect, 
  403.                     bis_origin,
  404.                     bis_vector,
  405.                     untrimmed_loop[icnt_prev],
  406.                     trimmed_loop[icnt]);
  407.  
  408.          /* Draw Fillet */
  409.          draw_fillet_triangle_plain (trimmed_loop[icnt_prev],
  410.                                trimmed_loop[icnt],
  411.                                sect,
  412.                                face,
  413.                                front_color,
  414.                                back_color);
  415.  
  416.          VEC_COPY ( (&cap_loop[3*iloop]), sect);
  417.          iloop ++;
  418.          VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[icnt])); 
  419.          iloop++;
  420.       }
  421.  
  422.       /* Case 3 -- add to collection of points */
  423.       if (!is_trimmed[icnt_prev] && !is_trimmed[icnt]) {
  424.          VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[icnt])); 
  425.          iloop++; 
  426.       } 
  427.  
  428.       /* Case 4 -- Hah! last point!  draw fillet & draw cap!  */
  429.       if (!is_trimmed[icnt_prev] && is_trimmed[icnt]) {
  430.          was_trimmed = TRUE;
  431.  
  432.          /* important note: the array "untrimmed" contains valid
  433.           * untrimmed data ONLY when is_trim is TRUE.  Otherwise, 
  434.           * only "trim" containes valid data */
  435.  
  436.          /* compute intersection */
  437.          INNERSECT (sect, 
  438.                     bis_origin,
  439.                     bis_vector,
  440.                     trimmed_loop[icnt_prev],
  441.                     untrimmed_loop[icnt]);
  442.  
  443.          /* Draw Fillet */
  444.          draw_fillet_triangle_plain (trimmed_loop[icnt_prev],
  445.                                trimmed_loop[icnt],
  446.                                sect,
  447.                                face,
  448.                                front_color,
  449.                                back_color);
  450.  
  451.          VEC_COPY ( (&cap_loop[3*iloop]), sect);
  452.          iloop ++;
  453.  
  454.          /* draw cap */
  455.          if (iloop >= 3) (*cap_callback) (iloop, 
  456.                                           (gleDouble (*)[3]) cap_loop, 
  457.                                           front_color,
  458.                                           cut_vector,
  459.                                           bis_vector,
  460.                                           NULL,
  461.                                           face);
  462.  
  463.          /* reset cap counter */
  464.          iloop = 0;
  465.       }
  466.    }
  467.  
  468.    /* now, finish up in the same way that we started.  If the last
  469.     * point of the contour is visible, drop an edge to the bisecting 
  470.     * plane, thus finishing the join, and then, draw the join! */
  471.  
  472.    icnt --;  /* decrement to make up for loop exit condititons */
  473.    icnt += ncp;
  474.    icnt %= ncp;
  475.    if ((!is_trimmed[icnt]) && (iloop >= 2))  {
  476.    
  477.       VEC_SUM (tmp_vec, trimmed_loop[icnt], bis_vector);
  478.       INNERSECT (sect, 
  479.                  bis_origin,
  480.                  bis_vector,
  481.                  trimmed_loop[icnt],
  482.                  tmp_vec);
  483.       VEC_COPY ( (&cap_loop[3*iloop]), sect);
  484.       iloop ++;
  485.  
  486.       /* if nothing was ever trimmed, then we want to draw the 
  487.        * cap the way the user asked for it -- closed or not closed.
  488.        * Therefore, reset the closure flag to its original state.
  489.        */
  490.       if (!was_trimmed) {
  491.          gleSetJoinStyle (save_style);
  492.       }
  493.  
  494.       /* draw cap */
  495.       (*cap_callback) (iloop, 
  496.                        (gleDouble (*)[3]) cap_loop, 
  497.                        front_color,
  498.                        cut_vector,
  499.                        bis_vector,
  500.                        NULL,
  501.                        face);
  502.    }
  503.  
  504.    /* rest to the saved style */
  505.    gleSetJoinStyle (save_style);
  506.    free (cap_loop);
  507. }
  508.  
  509. /* ============================================================ */
  510.  
  511. void draw_fillets_and_join_n_norms
  512.                     (int ncp, 
  513.                     gleDouble trimmed_loop[][3],
  514.                     gleDouble untrimmed_loop[][3], 
  515.                     int is_trimmed[],
  516.                     gleDouble bis_origin[3], 
  517.                     gleDouble bis_vector[3], 
  518.                     double normals[][3],
  519.                     float front_color[3],
  520.                     float back_color[3],
  521.                     gleDouble cut_vector[3], 
  522.                     int face,
  523.                     void ((*cap_callback) (int iloop,
  524.                                   double cap[][3],
  525.                                   float face_color[3],
  526.                                   gleDouble cut_vector[3],
  527.                                   gleDouble bisect_vector[3],
  528.                                   double norms[][3],
  529.                                   int frontwards)))
  530. {
  531.    int istop;
  532.    int icnt, icnt_prev, iloop;
  533.    double *cap_loop, *norm_loop;
  534.    gleDouble sect[3];
  535.    gleDouble tmp_vec[3];
  536.    int save_style;
  537.    int was_trimmed = FALSE;
  538.  
  539.    cap_loop = (double *) malloc ((ncp+3)*3*2*sizeof (double));
  540.    norm_loop = cap_loop + (ncp+3)*3;
  541.    
  542.    /* if the first point on the contour isn't trimmed, go ahead and
  543.     * drop an edge down to the bisecting plane, (thus starting the 
  544.     * join).  (Only need to do this for cut join, its bad if done for
  545.     * round join).
  546.     *
  547.     * But if the first point is trimmed, keep going until one
  548.     * is found that is not trimmed, and start join there.  */
  549.  
  550.    icnt = 0;
  551.    iloop = 0;
  552.    if (!is_trimmed[0]) {
  553.       if (__TUBE_CUT_JOIN) {
  554.          VEC_SUM (tmp_vec, trimmed_loop[0], bis_vector);
  555.          INNERSECT (sect, 
  556.                     bis_origin,
  557.                     bis_vector,
  558.                     trimmed_loop[0],
  559.                     tmp_vec);
  560.          VEC_COPY ( (&cap_loop[3*iloop]), sect);
  561.          VEC_COPY ( (&norm_loop[3*iloop]), normals[0]);
  562.          iloop ++;
  563.       }
  564.       VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[0])); 
  565.       VEC_COPY ( (&norm_loop[3*iloop]), normals[0]);
  566.       iloop++;
  567.       icnt_prev = icnt;
  568.       icnt ++;
  569.    } else {
  570.  
  571.       /* else, loop until an untrimmed point is found */
  572.       was_trimmed = TRUE;
  573.       while (is_trimmed[icnt]) {
  574.          icnt_prev = icnt;
  575.          icnt ++;
  576.          if (icnt >= ncp) {
  577.             free (cap_loop);
  578.             return;    /* oops - everything was trimmed */
  579.          }
  580.       }
  581.    }
  582.  
  583.    /* Start walking around the end cap.  Every time the end loop is
  584.     * trimmed, we know we'll need to draw a fillet triangle.  In
  585.     * addition, after every pair of visibility changes, we draw a cap. */
  586.    if (__TUBE_CLOSE_CONTOUR) {
  587.       istop = ncp;
  588.    } else {
  589.       istop = ncp-1;
  590.    }
  591.  
  592.    /* save the join style, and disable a closed contour.
  593.     * Need to do this so partial contours don't close up. */
  594.    save_style = gleGetJoinStyle ();
  595.    gleSetJoinStyle (save_style & ~TUBE_CONTOUR_CLOSED);
  596.  
  597.    for (; icnt_prev < istop; icnt_prev ++, icnt ++, icnt %= ncp) {
  598.  
  599.       /* There are four interesting cases for drawing caps and fillets:
  600.        *    1) this & previous point were trimmed.  Don't do anything, 
  601.        *       advance counter.
  602.        *    2) this point trimmed, previous not -- draw fillet, and 
  603.        *       draw cap.
  604.        *    3) this point not trimmed, previous one was -- compute
  605.        *       intersection point, draw fillet with it, and save 
  606.        *       point for cap contour.
  607.        *    4) this & previous point not trimmed -- save for endcap.
  608.        */
  609.  
  610.       /* Case 1 -- noop, just advance pointers */
  611.       if (is_trimmed[icnt_prev] && is_trimmed[icnt]) {
  612.       }
  613.  
  614.       /* Case 2 --  Hah! first point! compute intersect & draw fillet! */
  615.       if (is_trimmed[icnt_prev] && !is_trimmed[icnt]) {
  616.  
  617.          /* important note: the array "untrimmed" contains valid
  618.           * untrimmed data ONLY when is_trim is TRUE.  Otherwise, 
  619.           * only "trim" containes valid data */
  620.  
  621.          /* compute intersection */
  622.          INNERSECT (sect, 
  623.                     bis_origin,
  624.                     bis_vector,
  625.                     untrimmed_loop[icnt_prev],
  626.                     trimmed_loop[icnt]);
  627.  
  628.          /* Draw Fillet */
  629.          draw_fillet_triangle_n_norms (trimmed_loop[icnt_prev],
  630.                                trimmed_loop[icnt],
  631.                                sect,
  632.                                face,
  633.                                front_color,
  634.                                back_color,
  635.                                normals[icnt_prev],
  636.                                normals[icnt]);
  637.          VEC_COPY ( (&cap_loop[3*iloop]), sect);
  638.          VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt_prev]);
  639.          iloop ++;
  640.          VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[icnt])); 
  641.          VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt]);
  642.          iloop++;
  643.       }
  644.  
  645.       /* Case 3 -- add to collection of points */
  646.       if (!is_trimmed[icnt_prev] && !is_trimmed[icnt]) {
  647.          VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[icnt])); 
  648.          VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt]);
  649.          iloop++; 
  650.       } 
  651.  
  652.       /* Case 4 -- Hah! last point!  draw fillet & draw cap!  */
  653.       if (!is_trimmed[icnt_prev] && is_trimmed[icnt]) {
  654.          was_trimmed = TRUE;
  655.  
  656.          /* important note: the array "untrimmed" contains valid
  657.           * untrimmed data ONLY when is_trim is TRUE.  Otherwise, 
  658.           * only "trim" containes valid data */
  659.  
  660.          /* compute intersection */
  661.          INNERSECT (sect, 
  662.                     bis_origin,
  663.                     bis_vector,
  664.                     trimmed_loop[icnt_prev],
  665.                     untrimmed_loop[icnt]);
  666.  
  667.          /* Draw Fillet */
  668.          draw_fillet_triangle_n_norms (trimmed_loop[icnt_prev],
  669.                                trimmed_loop[icnt],
  670.                                sect,
  671.                                face,
  672.                                front_color,
  673.                                back_color,
  674.                                normals[icnt_prev],
  675.                                normals[icnt]);
  676.  
  677.          VEC_COPY ( (&cap_loop[3*iloop]), sect);
  678.  
  679.          /* OK, maybe phong normals are wrong, but at least facet
  680.           * normals will come out OK. */
  681.          if (__TUBE_DRAW_FACET_NORMALS) {
  682.             VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt_prev]);
  683.          } else {
  684.             VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt]);
  685.          }
  686.          iloop ++;
  687.  
  688.          /* draw cap */
  689.          if (iloop >= 3) (*cap_callback) (iloop, 
  690.                                           (gleDouble (*)[3]) cap_loop, 
  691.                                           front_color,
  692.                                           cut_vector,
  693.                                           bis_vector,
  694.                                           (gleDouble (*)[3]) norm_loop,
  695.                                           face);
  696.  
  697.          /* reset cap counter */
  698.          iloop = 0;
  699.       }
  700.    }
  701.  
  702.    /* now, finish up in the same way that we started.  If the last
  703.     * point of the contour is visible, drop an edge to the bisecting 
  704.     * plane, thus finishing the join, and then, draw the join! */
  705.  
  706.    icnt --;  /* decrement to make up for loop exit condititons */
  707.    icnt += ncp;
  708.    icnt %= ncp;
  709.    if ((!is_trimmed[icnt]) && (iloop >= 2))  {
  710.    
  711.       if (__TUBE_CUT_JOIN) {
  712.          VEC_SUM (tmp_vec, trimmed_loop[icnt], bis_vector);
  713.          INNERSECT (sect, 
  714.                     bis_origin,
  715.                     bis_vector,
  716.                     trimmed_loop[icnt],
  717.                     tmp_vec);
  718.          VEC_COPY ( (&cap_loop[3*iloop]), sect);
  719.          VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt]);
  720.          iloop ++;
  721.       }
  722.  
  723.       /* if nothing was ever trimmed, then we want to draw the 
  724.        * cap the way the user asked for it -- closed or not closed.
  725.        * Therefore, reset the closure flag to its original state.
  726.        */
  727.       if (!was_trimmed) {
  728.          gleSetJoinStyle (save_style);
  729.       }
  730.  
  731.       /* draw cap */
  732.       (*cap_callback) (iloop, 
  733.                        (gleDouble (*)[3]) cap_loop, 
  734.                        front_color,
  735.                        cut_vector,
  736.                        bis_vector,
  737.                        (gleDouble (*)[3]) norm_loop,
  738.                        face);
  739.    }
  740.  
  741.    /* rest to the saved style */
  742.    gleSetJoinStyle (save_style);
  743.    free (cap_loop);
  744. }
  745.  
  746. /* ============================================================ */
  747. /* This routine draws "cut" style extrusions.  
  748.  */
  749.  
  750. void extrusion_round_or_cut_join (int ncp,    /* number of contour points */
  751.                            gleDouble contour[][2],    /* 2D contour */
  752.                            gleDouble cont_normal[][2],/* 2D normal vecs */
  753.                            gleDouble up[3],    /* up vector for contour */
  754.                            int npoints,        /* numpoints in poly-line */
  755.                            gleDouble point_array[][3],    /* polyline */
  756.                            float color_array[][3],    /* color of polyline */
  757.                            gleDouble xform_array[][2][3])   /* 2D contour xforms */
  758. {
  759.    int i, j;
  760.    int inext, inextnext;
  761.    gleDouble m[4][4];
  762.    gleDouble tube_len, seg_len;
  763.    gleDouble diff[3];
  764.    gleDouble bi_0[3], bi_1[3];        /* bisecting plane */
  765.    gleDouble bisector_0[3], bisector_1[3];        /* bisecting plane */
  766.    gleDouble cut_0[3], cut_1[3];    /* cutting planes */
  767.    gleDouble lcut_0[3], lcut_1[3];    /* cutting planes */
  768.    int valid_cut_0, valid_cut_1;    /* flag -- cut vector is valid */
  769.    gleDouble end_point_0[3], end_point_1[3]; 
  770.    gleDouble torsion_point_0[3], torsion_point_1[3]; 
  771.    gleDouble isect_point[3];
  772.    gleDouble origin[3], neg_z[3];
  773.    gleDouble yup[3];        /* alternate up vector */
  774.    gleDouble *front_cap, *back_cap;    /* arrays containing the end caps */
  775.    gleDouble *front_loop, *back_loop; /* arrays containing the tube ends */
  776.    double *front_norm, *back_norm; /* arrays containing normal vecs */
  777.    double *norm_loop, *tmp; /* normal vectors, cast into 3d from 2d */
  778.    int *front_is_trimmed, *back_is_trimmed;   /* T or F */
  779.    float *front_color, *back_color;  /* pointers to segment colors */
  780.    void ((*cap_callback) ());  /* function callback to draw cap */
  781.    void ((*tmp_cap_callback) ());  /* function callback to draw cap */
  782.    int join_style_is_cut;      /* TRUE if join style is cut */
  783.    double dot;                  /* partial dot product */
  784.    char *mem_anchor;
  785.    int first_time = TRUE;
  786.    gleDouble *cut_vec;
  787.  
  788.    /* create a local, block scope copy of of the join style.
  789.     * this will alleviate wasted cycles and register write-backs */
  790.    /* choose the right callback, depending on the choosen join style */
  791.    if (__TUBE_CUT_JOIN) {
  792.       join_style_is_cut = TRUE;
  793.       cap_callback =  draw_cut_style_cap_callback;
  794.    } else {
  795.       join_style_is_cut = FALSE;
  796.       cap_callback =  draw_round_style_cap_callback;
  797.    }
  798.  
  799.    /* By definition, the contour passed in has its up vector pointing in
  800.     * the y direction */
  801.    if (up == NULL) {
  802.       yup[0] = 0.0;
  803.       yup[1] = 1.0;
  804.       yup[2] = 0.0;
  805.    } else {
  806.       VEC_COPY (yup, up);
  807.    }
  808.  
  809.    /* ========== "up" vector sanity check ========== */
  810.    (void) up_sanity_check (yup, npoints, point_array);
  811.  
  812.    /* the origin is at the origin */
  813.    origin [0] = 0.0;
  814.    origin [1] = 0.0;
  815.    origin [2] = 0.0;
  816.  
  817.    /* and neg_z is at neg z */
  818.    neg_z[0] = 0.0;
  819.    neg_z[1] = 0.0;
  820.    neg_z[2] = 1.0;
  821.  
  822.    /* malloc the data areas that we'll need to store the end-caps */
  823.    mem_anchor = malloc (4 * 3*ncp*sizeof(gleDouble)
  824.                       + 2 * 3*ncp*sizeof(double)
  825.                       + 2 * 1*ncp*sizeof(int));
  826.    front_norm = (double *) mem_anchor;
  827.    back_norm = front_norm + 3*ncp;
  828.    front_loop = (gleDouble *) (back_norm + 3*ncp);
  829.    back_loop = front_loop + 3*ncp;
  830.    front_cap = back_loop + 3*ncp;
  831.    back_cap  = front_cap + 3*ncp;
  832.    front_is_trimmed = (int *) (back_cap + 3*ncp);
  833.    back_is_trimmed = front_is_trimmed + ncp;
  834.  
  835.    /* ======================================= */
  836.  
  837.    /* |-|-|-|-|-|-|-|-| SET UP FOR FIRST SEGMENT |-|-|-|-|-|-|-| */
  838.  
  839.    /* ignore all segments of zero length */
  840.    i = 1;
  841.    inext = i;
  842.    FIND_NON_DEGENERATE_POINT (inext, npoints, seg_len, diff, point_array);
  843.    tube_len = seg_len;    /* store for later use */
  844.  
  845.    /* may as well get the normals set up now */
  846.    if (cont_normal != NULL) {
  847.       if (xform_array == NULL) {
  848.          norm_loop = front_norm;
  849.          back_norm = norm_loop;
  850.          for (j=0; j<ncp; j++) {
  851.             norm_loop[3*j] = cont_normal[j][0];
  852.             norm_loop[3*j+1] = cont_normal[j][1];
  853.             norm_loop[3*j+2] = 0.0;
  854.          }
  855.       } else {
  856.          for (j=0; j<ncp; j++) {
  857.             NORM_XFORM_2X2 ( (&front_norm[3*j]),
  858.                               xform_array[inext-1],
  859.                               cont_normal [j]);
  860.             front_norm[3*j+2] = 0.0;
  861.             back_norm[3*j+2] = 0.0;
  862.          }
  863.       }
  864.    } else {
  865.       front_norm = back_norm = norm_loop = NULL;
  866.    }
  867.  
  868.    /* get the bisecting plane */
  869.    bisecting_plane (bi_0, point_array[i-1], 
  870.                           point_array[i], 
  871.                           point_array[inext]);
  872.  
  873.    /* compute cutting plane */
  874.    CUTTING_PLANE (valid_cut_0, cut_0, point_array[i-1], 
  875.                          point_array[i], 
  876.                          point_array[inext]);
  877.    
  878.    /* reflect the up vector in the bisecting plane */
  879.    VEC_REFLECT (yup, yup, bi_0);
  880.  
  881.    /* |-|-|-|-|-|-|-|-| START LOOP OVER SEGMENTS |-|-|-|-|-|-|-| */
  882.  
  883.    /* draw tubing, not doing the first segment */
  884.    while (inext<npoints-1) {
  885.  
  886.       inextnext = inext;
  887.       /* ignore all segments of zero length */
  888.       FIND_NON_DEGENERATE_POINT (inextnext, npoints, 
  889.                                  seg_len, diff, point_array);
  890.  
  891.       /* get the far bisecting plane */
  892.       bisecting_plane (bi_1, point_array[i], 
  893.                              point_array[inext], 
  894.                              point_array[inextnext]);
  895.  
  896.  
  897.       /* compute cutting plane */
  898.       CUTTING_PLANE (valid_cut_1, cut_1, point_array[i], 
  899.                             point_array[inext], 
  900.                             point_array[inextnext]);  
  901.  
  902.       /* rotate so that z-axis points down v2-v1 axis, 
  903.        * and so that origen is at v1 */
  904.       uviewpoint (m, point_array[i], point_array[inext], yup);
  905.       PUSHMATRIX ();
  906.       MULTMATRIX (m);
  907.  
  908.       /* rotate the cutting planes into the local coordinate system */
  909.       MAT_DOT_VEC_3X3 (lcut_0, m, cut_0);
  910.       MAT_DOT_VEC_3X3 (lcut_1, m, cut_1);
  911.  
  912.       /* rotate the bisecting planes into the local coordinate system */
  913.       MAT_DOT_VEC_3X3 (bisector_0, m, bi_0);
  914.       MAT_DOT_VEC_3X3 (bisector_1, m, bi_1);
  915.  
  916.  
  917.       neg_z[2] = -tube_len;
  918.  
  919.       /* draw the tube */
  920.       /* --------- START OF TMESH GENERATION -------------- */
  921.       for (j=0; j<ncp; j++) {
  922.  
  923.          /* set up the endpoints for segment clipping */
  924.          if (xform_array == NULL) {
  925.             VEC_COPY_2 (end_point_0, contour[j]);
  926.             VEC_COPY_2 (end_point_1, contour[j]);
  927.             VEC_COPY_2 (torsion_point_0, contour[j]);
  928.             VEC_COPY_2 (torsion_point_1, contour[j]);
  929.          } else {
  930.             /* transform the contour points with the local xform */
  931.             MAT_DOT_VEC_2X3 (end_point_0,
  932.                              xform_array[inext-1], contour[j]);
  933.             MAT_DOT_VEC_2X3 (torsion_point_0,
  934.                              xform_array[inext], contour[j]);
  935.             MAT_DOT_VEC_2X3 (end_point_1,
  936.                              xform_array[inext], contour[j]);
  937.             MAT_DOT_VEC_2X3 (torsion_point_1,
  938.                              xform_array[inext-1], contour[j]);
  939.  
  940.             /* if there are normals and there are affine xforms,
  941.              * then compute local coordinate system normals.
  942.              * Set up the back normals. (The front normals we inherit
  943.              * from previous pass through the loop).  */
  944.             if (cont_normal != NULL) {
  945.                /* do up the normal vectors with the inverse transpose */
  946.                NORM_XFORM_2X2 ( (&back_norm[3*j]),
  947.                                 xform_array[inext],
  948.                                 cont_normal [j]);
  949.             }
  950.          }
  951.          end_point_0 [2] = 0.0;
  952.          torsion_point_0 [2] = 0.0;
  953.          end_point_1 [2] = - tube_len;
  954.          torsion_point_1 [2] = - tube_len;
  955.  
  956.          /* The two end-points define a line.  Intersect this line
  957.           * against the clipping plane defined by the PREVIOUS
  958.           * tube segment.  */
  959.  
  960.          /* if this and the last tube are co-linear, don't cut the angle
  961.           * if you do, a divide by zero will result.  This and last tube
  962.           * are co-linear when the cut vector is of zero length */
  963.          if (valid_cut_0 && join_style_is_cut) {
  964.              INNERSECT (isect_point,  /* isect point (returned) */
  965.                        origin,        /* point on intersecting plane */
  966.                        lcut_0,        /* normal vector to plane */
  967.                        end_point_0,    /* point on line */
  968.                        end_point_1);    /* another point on the line */    
  969.  
  970.             /* determine whether the raw end of the extrusion would have
  971.              * been cut, by checking to see if the raw and is on the 
  972.              * far end of the half-plane defined by the cut vector.
  973.              * If the raw end is not "cut", then it is "trimmed".
  974.              */
  975.             if (lcut_0[2] < 0.0) { VEC_SCALE (lcut_0, -1.0, lcut_0); }
  976.             dot = lcut_0[0] * end_point_0[0];
  977.             dot += lcut_0[1] * end_point_0[1];
  978.  
  979.             VEC_COPY ((&front_loop[3*j]), isect_point);
  980.          } else {
  981.             /* actual value of dot not interseting; need 
  982.              * only be positive so that if test below failes */
  983.             dot = 1.0;   
  984.             VEC_COPY ((&front_loop[3*j]), end_point_0);
  985.          }
  986.  
  987.          INNERSECT (isect_point,     /* intersection point (returned) */
  988.                     origin,        /* point on intersecting plane */
  989.                     bisector_0,        /* normal vector to plane */
  990.                     end_point_0,    /* point on line */
  991.                     torsion_point_1);    /* another point on the line */    
  992.  
  993.          /* trim out interior of intersecting tube */
  994.          /* ... but save the untrimmed version for drawing the endcaps */
  995.          /* ... note that cap contains valid data ONLY when is_trimmed
  996.           * is TRUE. */
  997.          if ((dot <= 0.0) || (isect_point[2] < front_loop[3*j+2])) {
  998. /*
  999.          if ((dot <= 0.0) || (front_loop[3*j+2] > 0.0)) {
  1000. */
  1001.             VEC_COPY ((&front_cap[3*j]), (&front_loop [3*j]));
  1002.             VEC_COPY ((&front_loop[3*j]), isect_point);
  1003.             front_is_trimmed[j] = TRUE;
  1004.          } else {
  1005.             front_is_trimmed[j] = FALSE;
  1006.          }
  1007.  
  1008.          /* if intersection is behind the end of the segment, 
  1009.           * truncate to the end of the segment
  1010.           * Note that coding front_loop [3*j+2] = -tube_len;
  1011.           * doesn't work when twists are involved, */
  1012.          if (front_loop[3*j+2] < -tube_len) {
  1013.             VEC_COPY( (&front_loop[3*j]), end_point_1);
  1014.          } 
  1015.  
  1016.          /* --------------------------------------------------- */
  1017.          /* The two end-points define a line.  We did one endpoint 
  1018.           * above. Now do the other.Intersect this line
  1019.           * against the clipping plane defined by the NEXT
  1020.           * tube segment.  */
  1021.  
  1022.          /* if this and the last tube are co-linear, don't cut the angle
  1023.           * if you do, a divide by zero will result.  This and last tube
  1024.           * are co-linear when the cut vector is of zero length */
  1025.          if (valid_cut_1 && join_style_is_cut) {
  1026.             INNERSECT (isect_point,  /* isect point (returned) */
  1027.                        neg_z,        /* point on intersecting plane */
  1028.                        lcut_1,        /* normal vector to plane */
  1029.                        end_point_1,    /* point on line */
  1030.                        end_point_0);    /* another point on the line */    
  1031.  
  1032.             if (lcut_1[2] > 0.0) { VEC_SCALE (lcut_1, -1.0, lcut_1); }
  1033.             dot = lcut_1[0] * end_point_1[0];
  1034.             dot += lcut_1[1] * end_point_1[1];
  1035.  
  1036.    
  1037.             VEC_COPY ((&back_loop[3*j]), isect_point);
  1038.          } else {
  1039.             /* actual value of dot not interseting; need 
  1040.              * only be positive so that if test below failes */
  1041.             dot = 1.0;   
  1042.             VEC_COPY ((&back_loop[3*j]), end_point_1);
  1043.          }
  1044.  
  1045.          INNERSECT (isect_point,     /* intersection point (returned) */
  1046.                     neg_z,        /* point on intersecting plane */
  1047.                     bisector_1,        /* normal vector to plane */
  1048.                     torsion_point_0,    /* point on line */
  1049.                     end_point_1);    /* another point on the line */    
  1050.  
  1051.          /* cut out interior of intersecting tube */
  1052.          /* ... but save the uncut version for drawing the endcaps */
  1053.          /* ... note that cap contains valid data ONLY when is
  1054.           *_trimmed is TRUE. */
  1055. /*
  1056.         if ((dot <= 0.0) || (back_loop[3*j+2] < -tube_len)) {
  1057. */
  1058.         if ((dot <= 0.0) || (isect_point[2] > back_loop[3*j+2])) {
  1059.             VEC_COPY ((&back_cap[3*j]), (&back_loop [3*j]));
  1060.             VEC_COPY ((&back_loop[3*j]), isect_point);
  1061.             back_is_trimmed[j] = TRUE;
  1062.          } else {
  1063.             back_is_trimmed[j] = FALSE;
  1064.          }
  1065.  
  1066.          /* if intersection is behind the end of the segment, 
  1067.           * truncate to the end of the segment 
  1068.           * Note that coding back_loop [3*j+2] = 0.0;
  1069.           * doesn't work when twists are involved, */
  1070.          if (back_loop[3*j+2] > 0.0) {
  1071.             VEC_COPY( (&back_loop[3*j]), end_point_0);
  1072.          } 
  1073.       }
  1074.  
  1075.       /* --------- END OF TMESH GENERATION -------------- */
  1076.  
  1077.       /* |||||||||||||||||| START SEGMENT DRAW |||||||||||||||||||| */
  1078.       /* There are six different cases we can have for presence and/or
  1079.        * absecnce of colors and normals, and for interpretation of
  1080.        * normals. The blechy set of nested if statements below
  1081.        * branch to each of the six cases */
  1082.       if (xform_array == NULL) {
  1083.          if (color_array == NULL) {
  1084.             if (cont_normal == NULL) {
  1085.                draw_segment_plain (ncp, (gleVector *) front_loop, (gleVector *) back_loop, inext, seg_len);
  1086.             } else
  1087.             if (__TUBE_DRAW_FACET_NORMALS) {
  1088.                draw_segment_facet_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) norm_loop, 
  1089.                                      inext, seg_len);
  1090.             } else {
  1091.                draw_segment_edge_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) norm_loop,
  1092.                                     inext, seg_len);
  1093.             }
  1094.          } else {
  1095.             if (cont_normal == NULL) {
  1096.                draw_segment_color (ncp, (gleVector *) front_loop, (gleVector *) back_loop, 
  1097.                                    color_array[inext-1],
  1098.                                    color_array[inext], inext, seg_len);
  1099.             } else
  1100.             if (__TUBE_DRAW_FACET_NORMALS) {
  1101.                draw_segment_c_and_facet_n (ncp, 
  1102.                                    (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) norm_loop,
  1103.                                    color_array[inext-1],
  1104.                                    color_array[inext], inext, seg_len);
  1105.             } else {
  1106.                draw_segment_c_and_edge_n (ncp, 
  1107.                                    (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) norm_loop,
  1108.                                    color_array[inext-1],
  1109.                                    color_array[inext], inext, seg_len);
  1110.              }
  1111.           }
  1112.       } else {
  1113.          if (color_array == NULL) {
  1114.             if (cont_normal == NULL) {
  1115.                draw_segment_plain (ncp, (gleVector *) front_loop, (gleVector *) back_loop, inext, seg_len);
  1116.             } else 
  1117.             if (__TUBE_DRAW_FACET_NORMALS) {
  1118.                draw_binorm_segment_facet_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop,
  1119.                                                  (gleVector *) front_norm, (gleVector *) back_norm, 
  1120.                                                  inext, seg_len);
  1121.             } else {
  1122.                draw_binorm_segment_edge_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop,
  1123.                                                 (gleVector *) front_norm, (gleVector *) back_norm,
  1124.                                                 inext, seg_len);
  1125.             }
  1126.          } else {
  1127.             if (cont_normal == NULL) {
  1128.                draw_segment_color (ncp, (gleVector *) front_loop, (gleVector *) back_loop, 
  1129.                                    color_array[inext-1],
  1130.                                    color_array[inext], inext, seg_len);
  1131.             } else
  1132.             if (__TUBE_DRAW_FACET_NORMALS) {
  1133.                draw_binorm_segment_c_and_facet_n (ncp, 
  1134.                                    (gleVector *) front_loop, (gleVector *) back_loop, 
  1135.                                    (gleVector *) front_norm, (gleVector *) back_norm, 
  1136.                                    color_array[inext-1],
  1137.                                    color_array[inext], inext, seg_len);
  1138.             } else {
  1139.                draw_binorm_segment_c_and_edge_n (ncp, 
  1140.                                    (gleVector *) front_loop, (gleVector *) back_loop,
  1141.                                    (gleVector *) front_norm, (gleVector *) back_norm, 
  1142.                                    color_array[inext-1],
  1143.                                    color_array[inext], inext, seg_len);
  1144.              }
  1145.           }
  1146.       }
  1147.       /* |||||||||||||||||| END SEGMENT DRAW |||||||||||||||||||| */
  1148.  
  1149.       /* v^v^v^v^v^v^v^v^v  BEGIN END CAPS v^v^v^v^v^v^v^v^v^v^v^v */
  1150.  
  1151.       /* if end caps are required, draw them. But don't draw any
  1152.        * but the very first and last caps */
  1153.       if (first_time) {
  1154.          first_time = FALSE;
  1155.          tmp_cap_callback = cap_callback;
  1156.          cap_callback = null_cap_callback;
  1157.          if (__TUBE_DRAW_CAP) {
  1158.             if (color_array != NULL) C3F (color_array[inext-1]);
  1159.             draw_angle_style_front_cap (ncp, bisector_0, (gleDouble (*)[3]) front_loop);
  1160.          }
  1161.       }
  1162.       /* v^v^v^v^v^v^v^v^v  END END CAPS v^v^v^v^v^v^v^v^v^v^v^v */
  1163.  
  1164.       /* $$$$$$$$$$$$$$$$ BEGIN -1, FILLET & JOIN DRAW $$$$$$$$$$$$$$$$$ */
  1165.       /* 
  1166.        * Now, draw the fillet triangles, and the join-caps.
  1167.        */
  1168.       if (color_array != NULL) {
  1169.          front_color = color_array[inext-1];
  1170.          back_color = color_array[inext];
  1171.       } else {
  1172.          front_color = NULL;
  1173.          back_color = NULL;
  1174.       }
  1175.  
  1176.       if (cont_normal == NULL) {
  1177.          /* the flag valid-cut is true if the cut vector has a valid 
  1178.           * value (i.e. if a degenerate case has not occured). 
  1179.           */
  1180.          if (valid_cut_0) {
  1181.             cut_vec = lcut_0;
  1182.          } else {
  1183.             cut_vec = NULL;
  1184.          }
  1185.          draw_fillets_and_join_plain (ncp, 
  1186.                                   (gleVector *) front_loop,
  1187.                                   (gleVector *) front_cap, 
  1188.                                   front_is_trimmed,
  1189.                                   origin,
  1190.                                   bisector_0, 
  1191.                                   front_color,
  1192.                                   back_color,
  1193.                                   cut_vec,
  1194.                                   TRUE,
  1195.                                   cap_callback);
  1196.  
  1197.          /* v^v^v^v^v^v^v^v^v  BEGIN END CAPS v^v^v^v^v^v^v^v^v^v^v^v */
  1198.          if (inext == npoints-2) {
  1199.             if (__TUBE_DRAW_CAP) {
  1200.                if (color_array != NULL) C3F (color_array[inext]);
  1201.                draw_angle_style_back_cap (ncp, bisector_1, (gleDouble (*)[3]) back_loop);
  1202.                cap_callback = null_cap_callback;
  1203.             }
  1204.          } else {
  1205.             /* restore ability to draw cap */
  1206.             cap_callback = tmp_cap_callback;
  1207.          }
  1208.          /* v^v^v^v^v^v^v^v^v  END END CAPS v^v^v^v^v^v^v^v^v^v^v^v */
  1209.    
  1210.          /* the flag valid-cut is true if the cut vector has a valid 
  1211.           * value (i.e. if a degenerate case has not occured). 
  1212.           */
  1213.          if (valid_cut_1) {
  1214.             cut_vec = lcut_1;
  1215.          } else {
  1216.             cut_vec = NULL;
  1217.          }
  1218.          draw_fillets_and_join_plain (ncp, 
  1219.                                   (gleVector *) back_loop,
  1220.                                   (gleVector *) back_cap, 
  1221.                                   back_is_trimmed,
  1222.                                   neg_z,
  1223.                                   bisector_1, 
  1224.                                   back_color,
  1225.                                   front_color,
  1226.                                   cut_vec,
  1227.                                   FALSE,
  1228.                                   cap_callback);
  1229.       } else {
  1230.    
  1231.          /* the flag valid-cut is true if the cut vector has a valid 
  1232.           * value (i.e. if a degenerate case has not occured). 
  1233.           */
  1234.          if (valid_cut_0) {
  1235.             cut_vec = lcut_0;
  1236.          } else {
  1237.             cut_vec = NULL;
  1238.          }
  1239.          draw_fillets_and_join_n_norms (ncp, 
  1240.                                   (gleVector *) front_loop,
  1241.                                   (gleVector *) front_cap, 
  1242.                                   front_is_trimmed,
  1243.                                   origin,
  1244.                                   bisector_0, 
  1245.                                   (gleVector *) front_norm,
  1246.                                   front_color,
  1247.                                   back_color,
  1248.                                   cut_vec,
  1249.                                   TRUE,
  1250.                                   cap_callback);
  1251.    
  1252.          /* v^v^v^v^v^v^v^v^v  BEGIN END CAPS v^v^v^v^v^v^v^v^v^v^v^v */
  1253.          if (inext == npoints-2) {
  1254.             if (__TUBE_DRAW_CAP) {
  1255.                if (color_array != NULL) C3F (color_array[inext]);
  1256.                draw_angle_style_back_cap (ncp, bisector_1, (gleDouble (*)[3]) back_loop);
  1257.                cap_callback = null_cap_callback;
  1258.             }
  1259.          } else {
  1260.             /* restore ability to draw cap */
  1261.             cap_callback = tmp_cap_callback;
  1262.          }
  1263.          /* v^v^v^v^v^v^v^v^v  END END CAPS v^v^v^v^v^v^v^v^v^v^v^v */
  1264.  
  1265.          /* the flag valid-cut is true if the cut vector has a valid 
  1266.           * value (i.e. if a degenerate case has not occured). 
  1267.           */
  1268.          if (valid_cut_1) {
  1269.             cut_vec = lcut_1;
  1270.          } else {
  1271.             cut_vec = NULL;
  1272.          }
  1273.          draw_fillets_and_join_n_norms (ncp, 
  1274.                                   (gleVector *) back_loop,
  1275.                                   (gleVector *) back_cap, 
  1276.                                   back_is_trimmed,
  1277.                                   neg_z,
  1278.                                   bisector_1, 
  1279.                                   (gleVector *) back_norm,
  1280.                                   back_color,
  1281.                                   front_color,
  1282.                                   cut_vec,
  1283.                                   FALSE,
  1284.                                   cap_callback);
  1285.       }
  1286.  
  1287.       /* $$$$$$$$$$$$$$$$ END FILLET & JOIN DRAW $$$$$$$$$$$$$$$$$ */
  1288.  
  1289.       /* pop this matrix, do the next set */
  1290.       POPMATRIX ();
  1291.  
  1292.       /* slosh stuff over to next vertex */
  1293.       tmp = front_norm;
  1294.       front_norm = back_norm;
  1295.       back_norm = tmp;
  1296.  
  1297.       tube_len = seg_len;
  1298.       i = inext;
  1299.       inext = inextnext;
  1300.       VEC_COPY (bi_0, bi_1);
  1301.       VEC_COPY (cut_0, cut_1);
  1302.       valid_cut_0 = valid_cut_1;
  1303.  
  1304.       /* reflect the up vector in the bisecting plane */
  1305.       VEC_REFLECT (yup, yup, bi_0);
  1306.    }
  1307.    /* |-|-|-|-|-|-|-|-| END LOOP OVER SEGMENTS |-|-|-|-|-|-|-| */
  1308.  
  1309.    free (mem_anchor);
  1310.  
  1311. }
  1312.    
  1313. /* =================== END OF FILE =============================== */
  1314.